/*=================================================================================================
*   (c) Copyright 2016-2021 TangJie.                                                              |
*   All Rights Reserved.                                                                          |
*   @file    Task.c                                                                               |
*   @Author  Tangjie                                                                              |
*   @version 0.1                                                                                  |
*                                                                                                 |
*   @brief   Task Management and Schedule.														  |
*   @details Middle Software Layer.                                                               |
*                                                                                                 |
==================================================================================================*/

/*=================================================================================================
* [ Include header files ]                                                                        |                     |
*=================================================================================================*/
#include "Task.h"



/*=================================================================================================
* [ Global variants ]                                                                             |                     |
*=================================================================================================*/
static volatile uint8_t   g_u8ScheduleEnFlag = DISABLE;
static volatile uint8_t   g_u8CurrentTaskIndex = 0;
TaskCB_T  g_stTaskList[TASK_TOTAL_NUM];



/*=================================================================================================
* @brief  Initialize task block struct array
* @call   Call by task initialization function
* @input  Void
* @output Void
*=================================================================================================*/
void Task_InitTaskList()
{
	uint8_t u8Loop = 0;
	TaskCB_T stInitTaskCB = TASKCB_INIT_VAL;
	for(u8Loop=0; u8Loop<TASK_TOTAL_NUM; u8Loop++)
	{
		g_stTaskList[u8Loop] = stInitTaskCB;
	}
}


/*=================================================================================================
* @brief  Stop task scheduler, all task function is stop.
* @call   Call by application,when scheduler needs to be stopped
* @input  Void
* @output Void
*=================================================================================================*/
void Task_StopSchedule()
{
	g_u8ScheduleEnFlag = DISABLE;
}


/*=================================================================================================
* @brief  Start task scheduler, all task function will be scheduled.
* @call   Call by application,when scheduler needs to be started
* @input  Void
* @output Void
*=================================================================================================*/
void Task_StartSchedule()
{
	g_u8ScheduleEnFlag = ENABLE;
}


/*=================================================================================================
* @brief  Get the index of currently running task .
* @call   Call by application
* @input  Void
* @output Task index
*=================================================================================================*/
uint8_t Task_GetCurrentTaskIndex()
{
	return g_u8CurrentTaskIndex;
}


/*=================================================================================================
* @brief  Get the index of currently running task .
* @call   Call by application
* @input  Void
* @output Task index
*=================================================================================================*/
void Task_ClearCurrentTaskRunCnt()
{
	if(g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag == ENABLE)
	{
		g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag = DISABLE;
		g_stTaskList[g_u8CurrentTaskIndex].u16RunCnt = 0;
		g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag = ENABLE;
	}else
	{
		g_stTaskList[g_u8CurrentTaskIndex].u16RunCnt = 0;
	}
}


/*=================================================================================================
* @brief  Get the index of currently running task .
* @call   Call by application
* @input  Void
* @output Task index
*=================================================================================================*/
uint16_t Task_GetCurrentTaskRunCnt()
{
	return g_stTaskList[g_u8CurrentTaskIndex].u16RunCnt;
}

/*=================================================================================================
* @brief  Get the run counter value of one task
* @call   Call by application
* @input  Task index
* @output Run counter value
*=================================================================================================*/
uint16_t Task_GetRunCnt(uint8_t u8Taskindex)
{
	if(u8Taskindex >= TASK_TOTAL_NUM)
	{
		return DISABLE;
	}
	return g_stTaskList[u8Taskindex].u16RunCnt;
}


/*=================================================================================================
* @brief  Get the enable flag of one task
* @call   Call by application
* @input  Task index
* @output Enable flag
*=================================================================================================*/
uint8_t Task_GetTaskEnFlag(uint8_t u8Taskindex)
{
	if(u8Taskindex >= TASK_TOTAL_NUM)
	{
		return DISABLE;
	}
	return g_stTaskList[u8Taskindex].u8TaskEnFlag;
}



void Task_StopTask(uint8_t u8Taskindex)
{
	if(u8Taskindex >= TASK_TOTAL_NUM)
	{
		return;
	}
	if(g_stTaskList[u8Taskindex].u8TaskEnFlag == ENABLE)
	{
		g_stTaskList[u8Taskindex].u8TaskEnFlag = DISABLE;
		if(g_stTaskList[u8Taskindex].pfTaskStopCallBack != NULL)
		{
			g_stTaskList[u8Taskindex].pfTaskStopCallBack();
		}
		g_stTaskList[u8Taskindex].u16RunCnt = 0;
	}
}



void Task_StartTaskWithoutLmt(uint8_t u8Taskindex, uint32_t u32DelayTime, uint32_t u32CycleTime)
{
	if(u8Taskindex >= TASK_TOTAL_NUM)
	{
		return;
	}
	if(g_stTaskList[u8Taskindex].u8TaskEnFlag == DISABLE)
	{
		g_stTaskList[u8Taskindex].u16RunCnt = 0;
		g_stTaskList[u8Taskindex].u8RunCntLmtFlag = DISABLE;
		g_stTaskList[u8Taskindex].u32DelayTime = u32DelayTime;
		g_stTaskList[u8Taskindex].u32CycleTime = u32CycleTime;
		if(g_stTaskList[u8Taskindex].pfTaskStartCallBack != NULL)
		{
			g_stTaskList[u8Taskindex].pfTaskStartCallBack();
		}
		g_stTaskList[u8Taskindex].u8TaskEnFlag = ENABLE;
	}
}



void Task_StartTaskWithLmt(uint8_t u8Taskindex, uint32_t u32DelayTime, uint32_t u32CycleTime, uint16_t u16Runcntmax)
{
	if(u8Taskindex >= TASK_TOTAL_NUM)
	{
		return;
	}
	if(g_stTaskList[u8Taskindex].u8TaskEnFlag == DISABLE)
	{
		g_stTaskList[u8Taskindex].u16RunCnt = 0;
		g_stTaskList[u8Taskindex].u8RunCntLmtFlag = ENABLE;
		g_stTaskList[u8Taskindex].u16RunCntMax = u16Runcntmax;
		g_stTaskList[u8Taskindex].u32DelayTime = u32DelayTime;
		g_stTaskList[u8Taskindex].u32CycleTime = u32CycleTime;
		if(g_stTaskList[u8Taskindex].pfTaskStartCallBack != NULL)
		{
			g_stTaskList[u8Taskindex].pfTaskStartCallBack();
		}
		g_stTaskList[u8Taskindex].u8TaskEnFlag = ENABLE;
	}
}



void Task_SetTaskTime(uint8_t u8Taskindex, uint32_t u32DelayTime, uint32_t u32CycleTime)
{
	if(u8Taskindex >= TASK_TOTAL_NUM)
	{
		return;
	}
	if(g_stTaskList[u8Taskindex].u8TaskEnFlag == DISABLE)
	{
		g_stTaskList[u8Taskindex].u32DelayTime = u32DelayTime;
		g_stTaskList[u8Taskindex].u32CycleTime = u32CycleTime;
	}else
	{
		g_stTaskList[u8Taskindex].u8TaskEnFlag = DISABLE;
		g_stTaskList[u8Taskindex].u32DelayTime = u32DelayTime;
		g_stTaskList[u8Taskindex].u32CycleTime = u32CycleTime;
		g_stTaskList[u8Taskindex].u8TaskEnFlag = ENABLE;
	}
}


void Task_SetCurrTaskTime(uint32_t u32DelayTime, uint32_t u32CycleTime, uint8_t u8TaskEnable)
{
	if(g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag == DISABLE)
	{
		g_stTaskList[g_u8CurrentTaskIndex].u32DelayTime = u32DelayTime;
		g_stTaskList[g_u8CurrentTaskIndex].u32CycleTime = u32CycleTime;
	}else
	{
		// g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag = DISABLE;
		g_stTaskList[g_u8CurrentTaskIndex].u32DelayTime = u32DelayTime;
		g_stTaskList[g_u8CurrentTaskIndex].u32CycleTime = u32CycleTime;
		g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag = u8TaskEnable;
	}
}

void Task_TimeTick()
{
	uint8_t u8Loop = 0;
	if(g_u8ScheduleEnFlag == DISABLE)
	{
		return;
	}
	for(u8Loop=0; u8Loop<TASK_TOTAL_NUM; u8Loop++)
	{
		if((g_stTaskList[u8Loop].u8TaskEnFlag == ENABLE) && (g_stTaskList[u8Loop].u8TaskRunFlag == DISABLE))
		{
			if(g_stTaskList[u8Loop].u32DelayTime > 1 )
			{
				g_stTaskList[u8Loop].u32DelayTime--;
			}else
			{
				g_stTaskList[u8Loop].u32DelayTime = 0;
				g_stTaskList[u8Loop].u8TaskRunFlag = ENABLE;
			}
		}
	}
}



void Task_Schedule()
{
	if(g_u8ScheduleEnFlag == DISABLE)
	{
		return;
	}
	for(g_u8CurrentTaskIndex=0; g_u8CurrentTaskIndex<TASK_TOTAL_NUM; g_u8CurrentTaskIndex++)
	{
		if((g_stTaskList[g_u8CurrentTaskIndex].u8TaskEnFlag == ENABLE) && (g_stTaskList[g_u8CurrentTaskIndex].u8TaskRunFlag == ENABLE))
		{
			if(g_stTaskList[g_u8CurrentTaskIndex].pfTaskFunc != NULL)
			{
				g_stTaskList[g_u8CurrentTaskIndex].u32DelayTime  = g_stTaskList[g_u8CurrentTaskIndex].u32CycleTime;
				if(g_stTaskList[g_u8CurrentTaskIndex].u16RunCnt < TASK_RUNCNT_MAX)
				{
					g_stTaskList[g_u8CurrentTaskIndex].u16RunCnt++;
				}
				g_stTaskList[g_u8CurrentTaskIndex].pfTaskFunc();
				if((g_stTaskList[g_u8CurrentTaskIndex].u8RunCntLmtFlag == ENABLE)
					&& (g_stTaskList[g_u8CurrentTaskIndex].u16RunCnt >= g_stTaskList[g_u8CurrentTaskIndex].u16RunCntMax))
				{
					Task_StopTask(g_u8CurrentTaskIndex);
				}
				g_stTaskList[g_u8CurrentTaskIndex].u8TaskRunFlag = DISABLE;
			}else
			{
				Task_StopTask(g_u8CurrentTaskIndex);
			}
		}
	}
}



void Task_Init(const UserTaskConfig_T* puserTaskCfgs, uint8_t u8taskNums)
{
	uint8_t u8Loop = 0;
	Task_InitTaskList();
	if(u8taskNums > TASK_TOTAL_NUM)
	{
		return;
	}
	for(u8Loop = 0; u8Loop < u8taskNums; u8Loop++)
	{
		g_stTaskList[u8Loop] = puserTaskCfgs[u8Loop];
	}
	Task_StartSchedule();

}













